package avicit.bdp.dgs.qa.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.dgs.qa.dao.WorkOrderDAO;
import avicit.bdp.dgs.qa.dto.JobDTO;
import avicit.bdp.dgs.qa.dto.JobReportDTO;
import avicit.bdp.dgs.qa.dto.WorkOrderDTO;
import avicit.bdp.dgs.qa.dto.WorkOrderHistoryDTO;
import avicit.bdp.dgs.qa.utils.constant.QaConstant;
import avicit.bdp.dgs.qa.utils.enums.*;
import avicit.bdp.dgs.qa.utils.redis.RedisUtils;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.impl.SystemConstant;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.commons.utils.JsonHelper;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.Page;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2023-05-29
 * @类说明：WorkOrderService
 * @修改记录：
 * @注意事项：
 * @主要功能：工单管理Service
 */
@Service
public class WorkOrderService extends BaseService<WorkOrderDAO, WorkOrderDTO> {
    private static final Logger logger = LoggerFactory.getLogger(WorkOrderService.class);

    @Autowired
    private WorkOrderHistoryService historyService;

    @Autowired
    private JobService jobService;

    @Autowired
    private JobReportService jobReportService;

    @Autowired
    private ConvertColumnClient convertColumnClient;

    @Resource
    RedisUtils redisUtils;

    /**
     * 处理工单验证任务线程池
     */
    private ExecutorService executorService;

    /**
     * 新增工单
     * 使用场景：质量报告界面上，点击【立即处理】处理按钮，首次需要创建工单；其他仅返回工单ID即可；
     * @param workOrderDTO
     * @return
     */
    @Transactional
    public String addWorkOrder(WorkOrderDTO workOrderDTO) {
        // step1:合法性检查
        checkAddValid(workOrderDTO);

        // step2:工单已创建，直接返回工单ID
        WorkOrderDTO workOrder = getWorkOrderByJobAndInstanceId(workOrderDTO.getJobId(), workOrderDTO.getProcessInstanceId());
        if (workOrder != null) {
            return workOrder.getId();
        }

        // step3:质量作业首次执行，生成工单
        workOrderDTO.setId(ComUtil.getId());
        workOrderDTO.setDealUser(ThreadContextHelper.getUserId() == null ? "1" : ThreadContextHelper.getUserId());
        save2Db(workOrderDTO);

        // step4:生成工单历史记录
        WorkOrderHistoryDTO historyDTO = buildAddWorkOrderHistory(workOrderDTO);
        this.historyService.addHistory(historyDTO);
        BdpLogUtil.log4Insert(workOrderDTO);
        return workOrderDTO.getId();
    }

    /**
     * 删除/批量删除工单，多个id使用英文逗号隔开
     * @param id
     * @return
     */
    @Transactional
    public int deleteWorkOrder(String id) {
        if (StringUtils.isBlank(id)) {
            return 0;
        }

        for (String workOrderId : Arrays.asList(id.trim().split(Constants.COMMA))) {
            // 删除工单
            this.mapper.deleteWorkOrderByCond(Arrays.asList(workOrderId));

            // 删除工单历史记录
            this.historyService.deleteWorkOrderHistory(workOrderId);
        }

        String logTitle = "删除工单：【" + id + "】";
        BdpLogUtil.log("工单管理模块", logTitle, PlatformConstant.OpType.delete);
        return 0;
    }

    /**
     * 修改工单
     * @param workOrderDTO
     * @return
     */
    @Transactional
    public boolean updateWorkOrder(WorkOrderDTO workOrderDTO) {
        checkUpdateValid(workOrderDTO);

        update2Db(workOrderDTO);

        return true;
    }

    /**
     * 查询工单详情
     * @param id 工单ID
     * @return
     */
    @Transactional
    public WorkOrderDTO getWorkOrderInfo(String id) {
        if (StringUtils.isBlank(id)) {
            logger.warn("获取工单进本信息失败，工单ID为空");
            return null;
        }

        WorkOrderDTO dto = this.mapper.getWorkOrderDetail(id);
        if (dto == null) {
            logger.warn("未找到工单，工单ID：" + id);
            return null;
        }

        // 转换
        valueConvert(Arrays.asList(dto));

        String logTitle = "查看工单管理：【" + JSONObject.toJSONString(dto) + "】";
        BdpLogUtil.log("工单管理模块", logTitle, PlatformConstant.OpType.select);
        return dto;
    }

    /**
     * 查询工单详情
     * @param id 工单ID
     * @return
     */
    @Transactional
    public Map<String, Object> getWorkOrderDetail(String id) {
        if (StringUtils.isBlank(id)) {
            logger.warn("获取工单详情失败，工单ID为空");
            return new HashMap<>();
        }

        WorkOrderDTO workOrder = this.getWorkOrderInfo(id);
        if (workOrder == null) {
            logger.warn("未找到工单，工单ID：" + id);
            return new HashMap<>();
        }
        JobDTO job = this.jobService.getJobDetail(workOrder.getJobId());
        if (job == null) {
            logger.warn("未找到质量作业，工单ID：" + id + "，作业ID：" + workOrder.getJobId());
            return new HashMap<>();
        }

        Map<String, Object> report = this.jobService.queryReport(workOrder.getJobId(), workOrder.getProcessInstanceId());
        List<List<Object>> tableList = (List<List<Object>> )report.get("tableInfo");
        List<List<Object>> ruleList = (List<List<Object>> )report.get("ruleDetailInfo");

        // 填充告警表
        Map<String, Object> resultMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(tableList)) {
            resultMap.put("tableList", tableList);
        } else {
            resultMap.put("tableList", new ArrayList<>());
        }

        // 填充告警规则
        if (CollectionUtils.isNotEmpty(ruleList)) {
            resultMap.put("ruleList", ruleList);
        } else {
            resultMap.put("ruleList", new ArrayList<>());
        }

        return resultMap;
    }

    /**
     * 查询工单进度
     * @param id 工单ID
     * @return
     */
    @Transactional
    public List<WorkOrderHistoryDTO> getWorkOrderProgress(String id) {
        if (StringUtils.isBlank(id)) {
            logger.warn("获取工单进度失败，工单ID为空");
            return new ArrayList<>();
        }

        WorkOrderDTO workOrder = this.getWorkOrderInfo(id);
        if (workOrder == null) {
            logger.warn("未找到工单，工单ID：" + id);
            return new ArrayList<>();
        }

        return this.historyService.getWorkOrderHistoryList(id);
    }

    /**
     * 分页查询工单
     * 注意：
     *  1、自己创建的工单；
     *  2、登录用户和当前处理人一致，可以查看工单并进行处理；
     * @param keyWords
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Transactional
    public QueryRespBean<WorkOrderDTO> queryWorkOrder(String keyWords, Integer pageNo, Integer pageSize) {
        QueryRespBean<WorkOrderDTO> queryRespBean = new QueryRespBean<>();

        String loginUserId = ThreadContextHelper.getUserId();
        List<String> wordSecretList = ThreadContextHelper.getWordSecretList();
        com.github.pagehelper.PageHelper.startPage(pageNo, pageSize);
        Page<WorkOrderDTO> queryRet = this.mapper.queryWorkOrderByCond(keyWords, loginUserId, loginUserId, wordSecretList);
        valueConvert(queryRet.getResult());
        queryRespBean.setResult(queryRet);
        BdpLogUtil.log4Query(queryRespBean);
        return queryRespBean;
    }

    /**
     * 处理工单流转
     * @param workOrderDTO
     * @return
     */
    @Transactional
    public String flowWorkOrder(WorkOrderDTO workOrderDTO) {
        // step1:合法性检查
        checkFlowValid(workOrderDTO);

        // step2:根据ID查询工单
        WorkOrderDTO oldDto = this.selectByPrimaryKey(workOrderDTO.getId());
        if (oldDto == null) {
            throw new BusinessException("根据ID未找到工单，id=" + workOrderDTO.getId() + "，更新失败");
        }

        // step3:根据流转方式，确定状态
        workOrderDTO.setLevel(oldDto.getLevel());
        switch (WorkOrderProcessMode.getTypeByCode(workOrderDTO.getProcessMode())) {
            case ASSIGN:
                workOrderDTO.setState(WorkOrderState.HANDLE.getCode());
                break;
            case IGNORE:
                workOrderDTO.setDealUser(oldDto.getCreatedBy());// 工单重新流转到创建者手里
                workOrderDTO.setState(WorkOrderState.FINISHED.getCode());
                break;
            case MANUAL:
                workOrderDTO.setDealUser(oldDto.getCreatedBy());// 工单重新流转到创建者手里，请他验证
                workOrderDTO.setState(WorkOrderState.VERIFY.getCode());
                break;
            default:
        }

        // step4:更新工单状态
        update2Db(workOrderDTO);

        // step5:根据状态不同，分开处理历史记录
        workOrderDTO.setCurrDealUser(ThreadContextHelper.getUserId() == null ? "1" : ThreadContextHelper.getUserId());
        valueConvert(Arrays.asList(workOrderDTO));
        WorkOrderHistoryDTO historyDTO = new WorkOrderHistoryDTO();
        historyDTO.setId(ComUtil.getId());
        historyDTO.setWorkOrderId(workOrderDTO.getId());
        historyDTO.setState(workOrderDTO.getState());
        historyDTO.setSecretLevel(oldDto.getSecretLevel());
        StringBuffer content = new StringBuffer();
        switch (WorkOrderState.getTypeByCode(workOrderDTO.getState())) {
            case ASSIGN:
                content.append("系统生成工单，工单等级：" + WorkOrderLevel.getDescByCode(workOrderDTO.getLevel()));
                break;
            case HANDLE:
                content.append(String.format("【%s】指派【%s】为处理人。\n处理意见：%s",
                        workOrderDTO.getCurrDealUserName(), workOrderDTO.getDealUserName(), workOrderDTO.getSuggestion()));
                break;
            case VERIFY:
                content.append(String.format("【%s】已对工单进行处理。\n处理方式：%s。\n处理意见：%s",
                        workOrderDTO.getCurrDealUserName(), workOrderDTO.getProcessModeName(), workOrderDTO.getSuggestion()));
                break;
            case FINISHED:
                content.append(String.format("【%s】已对工单进行处理。\n处理方式：%s，已自动关闭工单。\n处理意见：%s",
                        workOrderDTO.getCurrDealUserName(), workOrderDTO.getProcessModeName(), workOrderDTO.getSuggestion()));
                break;
            default:
                content.append("未进行任何处理。");
        }
        historyDTO.setContent(content.toString());

        return this.historyService.addHistory(historyDTO);
    }

    /**
     * 处理工单流转
     * @param workOrderDTO
     * @return
     */
    @Transactional
    public String verifyWorkOrder(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO == null) {
            throw new BusinessException("入参为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getJobId())) {
            throw new BusinessException("质量作业ID为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getProcessInstanceId())) {
            throw new BusinessException("流程实例ID为空.");
        }

        // 重新执行质量任务
        this.jobService.executeJob(workOrderDTO.getJobId(), workOrderDTO.getProcessInstanceId(), null, 2, null);

        return workOrderDTO.getId();
    }

    /**
     * 忽略验证工单（已解决）
     * @param workOrderDTO
     * @return
     */
    @Transactional
    public String ingoreVerifyWorkOrder(WorkOrderDTO workOrderDTO) {
        // step1:合法性检查
        if (workOrderDTO == null) {
            throw new BusinessException("入参为空.");
        }

        // step2:更新工单状态
        WorkOrderDTO oldDto = this.selectByPrimaryKey(workOrderDTO.getId());
        if (oldDto == null) {
            throw new BusinessException("根据ID未找到工单，id=" + workOrderDTO.getId() + "，更新失败");
        }
        // step3:持久化
        workOrderDTO.setDealUser(oldDto.getCreatedBy());
        workOrderDTO.setState(WorkOrderState.FINISHED.getCode());
        this.updateByPrimaryKeySelective(workOrderDTO);

        // step4:历史记录
        WorkOrderHistoryDTO historyDTO = buildIngoreVerifyWorkOrderHistory(workOrderDTO);
        this.historyService.addHistory(historyDTO);

        // step5:审计日志
        BdpLogUtil.log4Update(workOrderDTO, oldDto);

        return workOrderDTO.getId();
    }

    /**
     * 对外接口：redis消息队列中拉取数据，处理待验证工单
     */
    public void run() {
        logger.info("DGS开启后台工单生成任务...");

        executorService = Executors.newFixedThreadPool(QaConstant.WORK_ORDER_FIXED_THREAD_NUM);
        while (true) {
            try {
                // step1:当前队列为空，延时处理
                if (redisUtils.llen(QaConstant.WORK_ORDER_REDIS_KEY) <= 0) {
                    continue;
                }

                // step2:获取上传文件信息OssUploadDto
                WorkOrderDTO workOrder = getWorkOrderFromRedis();
                if (workOrder == null) {
                    continue;
                }

                logger.info("从Redis获取一条工单请求，：\n" + JSONObject.toJSONString(workOrder));

                // step3:工单处理(注意：必须切换线程，否则单线程查询DB，结果保持一致，永远无法判断任务是否执行完毕)
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        generateWorkOrder(workOrder);
                    }
                });
            } catch (Exception e) {
                logger.error("后台从redis拉取工单失败,errMsg={}", e.getMessage());
            } finally {
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 新建工单时合法性检查
     * @param workOrderDTO
     */
    private void checkAddValid(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO == null) {
            throw new BusinessException("入参为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getName())) {
            throw new BusinessException("工单名字为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getJobId())) {
            throw new BusinessException("质量作业ID为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getProcessInstanceId())) {
            throw new BusinessException("流程实例ID为空.");
        }
    }

    /**
     * 更新工单时合法性检查
     * @param workOrderDTO
     */
    private void checkUpdateValid(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO == null) {
            throw new BusinessException("入参为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getId())) {
            throw new BusinessException("工单主键ID为空.");
        }
    }

    /**
     * 工单流转时合法性检查
     * @param workOrderDTO
     */
    private void checkFlowValid(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO == null) {
            throw new BusinessException("入参为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getId())) {
            throw new BusinessException("工单主键ID为空.");
        }
        if (StringUtils.isBlank(workOrderDTO.getSuggestion())) {
            throw new BusinessException("工单处理意见为空.");
        }
        if (workOrderDTO.getProcessMode() == null) {
            throw new BusinessException("工单处理方式为空.");
        }
    }

    /**
     * 生成工单合法性检查
     * @param workOrder
     * @return
     */
    private boolean checkGenerateWorkOrderValid(WorkOrderDTO workOrder) {
        if (workOrder == null) {
            return false;
        }
        if (StringUtils.isEmpty(workOrder.getName())) {
            logger.warn("从redis获取工单中不包含name，生成工单失败.");
            return false;
        }
        if (StringUtils.isEmpty(workOrder.getJobId())) {
            logger.warn("从redis获取工单中不包含jobId，生成工单失败.");
            return false;
        }
        if (StringUtils.isEmpty(workOrder.getProcessInstanceId())) {
            logger.warn("从redis获取工单中不包含processInstanceId，生成工单失败.");
            return false;
        }
        if (workOrder.getJobState() == null) {
            logger.warn("从redis获取工单中不包含jobState，生成工单失败.");
            return false;
        }

        return true;
    }

    /**
     * 持久化DB
     * @param workOrderDTO
     */
    private void save2Db(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO != null) {
            workOrderDTO.setVerifyTask(false);// true：验证任务；false：非验证任务
            workOrderDTO.setState(WorkOrderState.ASSIGN.getCode());// 状态，0:待指派、1:待处理、2:待验证、3:已完结
            workOrderDTO.setLevel(WorkOrderLevel.MEDIUM.getCode());// 工单级别，0:低、1:中、2:高

            JobDTO job = jobService.selectByPrimaryKey(workOrderDTO.getJobId());
            workOrderDTO.setSecretLevel(job.getSecretLevel());

            // 持久化
            this.insert(workOrderDTO);
        }
    }

    /**
     * 更新到DB
     * @param workOrderDTO
     */
    private void update2Db(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO == null) {
            return;
        }

        WorkOrderDTO oldDto = this.selectByPrimaryKey(workOrderDTO.getId());
        if (oldDto == null) {
            throw new BusinessException("根据ID未找到工单，id=" + workOrderDTO.getId() + "，更新失败");
        }

        // 持久化
        this.updateByPrimaryKeySelective(workOrderDTO);

        // 审计日志
        BdpLogUtil.log4Update(workOrderDTO, oldDto);
    }

    /**
     * 从redis获取工单
     * @return
     */
    private WorkOrderDTO getWorkOrderFromRedis() {
        String jsonData = redisUtils.rpop(QaConstant.WORK_ORDER_REDIS_KEY);
        if (jsonData == null) {
            return null;
        }

        return JsonHelper.getInstance().readValue(
                jsonData,
                new SimpleDateFormat(Constants.YYYY_MM_DD_HH_MM_SS),
                new TypeReference<WorkOrderDTO>() {
                });
    }

    /**
     * 根据redis中推送的工单信息，生成工单或更新历史记录
     * 注意：redis中工单信息仅包括：name、level、jobId、processInstanceId、jobState；
     * @param workOrder
     */
    private void generateWorkOrder(WorkOrderDTO workOrder) {
        // step1:合法性检查
        if (!checkGenerateWorkOrderValid(workOrder)) {
            return;
        }

        // step2:任务执行失败，不需要生成工单
        if (workOrder.getJobState() == JobState.FAIL.getCode()) {
            logger.warn(String.format("质量作业执行失败，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            return;
        }

        // step3:判断是否为工单验证任务，只有工单验证任务才处理
        WorkOrderDTO oldDto = getWorkOrderByJobAndInstanceId(workOrder.getJobId(), workOrder.getProcessInstanceId());
        if (oldDto == null) {
            logger.warn(String.format("质量作业并非工单验证任务，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            return;
        }
        workOrder.setId(oldDto.getId());
        workOrder.setDealUser(oldDto.getDealUser() == null ? ThreadContextHelper.getUserId() : oldDto.getDealUser());
        workOrder.setVerifyTask(true);

        // step4:判断DB中流程实例是否更新完状态
        if (checkTaskCompltedd(workOrder.getJobId(), workOrder.getProcessInstanceId())) {
            logger.warn(String.format("DDS中质量作业尚未更新状态，等待更新状态完毕，消息重新抛给redis,作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            redisUtils.lpush(QaConstant.WORK_ORDER_REDIS_KEY, JsonHelper.getInstance().writeValueAsString(workOrder));
            return;
        }

        // step5:重新生成质量报告(先删除、再更新)
        JobDTO jobDetail = this.jobService.getJobDetail(workOrder.getJobId());
        if (jobDetail == null) {
            logger.error("质量作业不存在，不需要工单处理，jobId：" + workOrder.getJobId());
            return;
        }
        JobReportDTO jobReport = this.jobReportService.regenerateReport(jobDetail, workOrder.getProcessInstanceId());

        // step6:任务执行失败，不需要工单处理
        if (jobReport != null) {
            JobResultType jobResultType = JobResultType.getTypeByCode(jobReport.getJobResultType());
            if (jobResultType == null || JobResultType.FAIL == jobResultType) {
                logger.warn(String.format("质量作业执行失败，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                        workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
                return;
            }
        }
        workOrder.setJobResultType(JobResultType.getTypeByCode(jobReport.getJobResultType()));

        // step7:处理工单
        handToBeVerifiedWorkOrder(workOrder);
    }

    /**
     * 根据质量作业ID和流程实例ID查询工单
     * @param jobId
     * @param processInstanceId
     * @return
     */
    private WorkOrderDTO getWorkOrderByJobAndInstanceId(String jobId, String processInstanceId) {
        List<WorkOrderDTO> workOrderList = this.mapper.getWorkOrderByCond(jobId, processInstanceId);
        if(CollectionUtils.isNotEmpty(workOrderList)) {
            WorkOrderDTO workOrder = workOrderList.get(0);
            if (workOrder != null) {
                return workOrder;
            }
        }

        return null;
    }

    /**
     * 判断是否需要等待任务执行完成，如果是工单重新推送给redis，否则直接处理
     * 注意：
     *  1、dds执行完任务后，调用API接口更新dgs中质量作业状态；
     *  2、更新完质量作业状态，推送工单消息到redis；
     *  3、工单后台任务从redis拉取消息，处理工单；
     *  4、步骤1/2和步骤3是异步操作，步骤3处理工单时可能出现dds中流程实例尚未更新DB的场景，所以要等待dds更新完DB才可以处理工单，否则会报错；
     * @param jobId
     * @param processInstanceId
     * @return
     */
    private boolean checkTaskCompltedd(String jobId, String processInstanceId) {
        Integer state = this.jobService.getProcessInstanceState(jobId, processInstanceId);
        if (state == null) {
            logger.warn(String.format("未找到流程实例.作业Id:%s,流程实例Id:%s", jobId, processInstanceId));
            return false;
        }

        // 流程实例运行中，需要将工单消息重新抛给redis，等待任务执行完成后再处理
        if (state.equals(1)) {
            return true;
        }

        return false;
    }

    /**
     * 验证任务执行完毕后，处理工单
     * @param workOrder
     */
    private void handToBeVerifiedWorkOrder(WorkOrderDTO workOrder) {
        logger.info("待处理工单信息：\n" + JSONObject.toJSONString(workOrder));

        // step1:对工单中处理人、创建人、状态等进行处理
        valueConvert(Arrays.asList(workOrder));

        // step3:构建历史记录
        WorkOrderHistoryDTO historyDTO = buildToBeVerifiedWorkOrderHistory(workOrder);
        logger.info("工单历史记录：" + JSONObject.toJSONString(historyDTO));

        // step4:更新工单状态
        workOrder.setState(historyDTO.getState());
        update2Db(workOrder);

        // step5:新增历史记录
        this.historyService.addHistory(historyDTO);
    }

    /**
     * 质量任务是否告警
     * @param workOrder
     */
    private JobResultType getJobResultType(WorkOrderDTO workOrder) {
        // step1:查看质量报告
        Map<String, Object> report = this.jobService.queryReport(workOrder.getJobId(), workOrder.getProcessInstanceId());
        if (report == null || report.size() <= 0) {
            logger.warn(String.format("质量报告为空，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            return JobResultType.FAIL;
        }
        if (!report.containsKey(QaConstant.SCORE_INFO)) {
            logger.warn(String.format("质量报告没有校验结果信息，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            return JobResultType.FAIL;
        }

        Map<String, Object> scoreInfo = (Map<String, Object>)report.get(QaConstant.SCORE_INFO);
        if (!scoreInfo.containsKey(QaConstant.RESULT)) {
            logger.warn(String.format("质量报告没有校验结果信息，不需要生成工单.作业名称:%s,作业Id:%s,流程实例Id:%s",
                    workOrder.getName(), workOrder.getJobId(), workOrder.getProcessInstanceId()));
            return JobResultType.FAIL;
        }
        String result = (String)scoreInfo.get(QaConstant.RESULT);

        JobResultType jobResultType = null;
        if (result.equals(QaConstant.JOB_NORAML)) {
            jobResultType = JobResultType.NORMAL;
        } else if (result.equals(QaConstant.JOB_ALERT)) {
            jobResultType = JobResultType.ALERT;
        } else {
            jobResultType = JobResultType.FAIL;
        }

        return jobResultType;
    }

    /**
     * 新建工单时，构建历史记录
     * @param workOrderDTO
     * @return
     */
    private WorkOrderHistoryDTO buildAddWorkOrderHistory(WorkOrderDTO workOrderDTO) {
        WorkOrderHistoryDTO historyDTO = new WorkOrderHistoryDTO();

        historyDTO.setId(ComUtil.getId());
        historyDTO.setState(WorkOrderState.ASSIGN.getCode());
        historyDTO.setWorkOrderId(workOrderDTO.getId());
        historyDTO.setContent("系统生成工单，工单等级：" + WorkOrderLevel.getDescByCode(workOrderDTO.getLevel()));

        JobDTO job = jobService.selectByPrimaryKey(workOrderDTO.getJobId());
        historyDTO.setSecretLevel(job.getSecretLevel());

        return historyDTO;
    }

    /**
     * 忽略验证时，构建历史记录
     * @param workOrderDTO
     * @return
     */
    private WorkOrderHistoryDTO buildIngoreVerifyWorkOrderHistory(WorkOrderDTO workOrderDTO) {
        WorkOrderHistoryDTO historyDTO = new WorkOrderHistoryDTO();

        historyDTO.setId(ComUtil.getId());
        historyDTO.setState(workOrderDTO.getState());
        historyDTO.setWorkOrderId(workOrderDTO.getId());
        workOrderDTO.setCurrDealUser(ThreadContextHelper.getUserId() == null ? "1" : ThreadContextHelper.getUserId());
        valueConvert(Arrays.asList(workOrderDTO));
        historyDTO.setContent( String.format("【%s】未对工单进行验证，手动解决该问题。工单自动关闭", workOrderDTO.getCurrDealUserName()));

        return historyDTO;
    }

    /**
     * 忽略验证时，构建历史记录
     * @param workOrderDTO
     * @return
     */
    private WorkOrderHistoryDTO buildToBeVerifiedWorkOrderHistory(WorkOrderDTO workOrderDTO) {
        WorkOrderHistoryDTO historyDTO = new WorkOrderHistoryDTO();

        historyDTO.setId(ComUtil.getId());
        historyDTO.setWorkOrderId(workOrderDTO.getId());
        StringBuffer content = new StringBuffer();
        JobResultType jobResultType = workOrderDTO.getJobResultType();
        switch (jobResultType) {
            case NORMAL:
                // 校验通过，关闭工单
                historyDTO.setState(WorkOrderState.FINISHED.getCode());// 已完结
                content.append(String.format("【%s】已对工单进行验证，当前数据通过质量稽核。工单自动关闭", workOrderDTO.getDealUserName()));
                break;
            case ALERT:
                // 校验未通过，工单重新流转
                historyDTO.setState(WorkOrderState.ASSIGN.getCode());// 待指派
                content.append(String.format("【%s】已对工单进行验证，当前数据未通过质量稽核。工单重新流转", workOrderDTO.getDealUserName()));
                break;
            default:
                // 工单验证任务失败，不做任何处理
                historyDTO.setState(workOrderDTO.getState());
        }
        historyDTO.setContent(content.toString());

        return historyDTO;
    }

    /**
     * 通过平台API将字段值转换为名称，包括通用选择组件、通用代码
     * @param dtoList
     */
    private void valueConvert(List<WorkOrderDTO> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return;
        }

        // 设置创建者名称
        Map<String, Set<String>> convertFormData = new HashMap<>();
        for (WorkOrderDTO dto : dtoList) {
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, dto.getCreatedBy());
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, dto.getDealUser());
            BusinessUtil.createConvertSet(convertFormData, SystemConstant.USER, dto.getCurrDealUser());
            BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, dto.getSecretLevel());
        }
        if (convertFormData.size() > 0) {
            //获取请求结果
            Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
            //循环设置Alias或Name的值
            for (WorkOrderDTO dto : dtoList) {
                if (StringUtils.isNotEmpty(dto.getCreatedBy())) {
                    dto.setCreatedBy(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, dto.getCreatedBy()));
                }
                if (StringUtils.isNotEmpty(dto.getDealUser())) {
                    dto.setDealUserName(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, dto.getDealUser()));
                }
                if (StringUtils.isNotEmpty(dto.getCurrDealUser())) {
                    dto.setCurrDealUserName(BusinessUtil.convertFormat(convertResultData, SystemConstant.USER, dto.getCurrDealUser()));
                }
                dto.setSecretLevelName(BusinessUtil.convertFormat(
                        convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, dto.getSecretLevel()));
            }
        }

        // 设置枚举类型
        for (WorkOrderDTO dto : dtoList) {
            dto.setStateName(WorkOrderState.getDescByCode(dto.getState()));
            dto.setLevelName(WorkOrderLevel.getDescByCode(dto.getLevel()));
            dto.setProcessModeName(WorkOrderProcessMode.getDescByCode(dto.getProcessMode()));

            // 设置“是否展示工单处理选项”
            setWorkOrderDisplay(dto);
        }
    }

    /**
     * 设置“是否展示工单处理选项”
     * @param dto
     */
    private void setWorkOrderDisplay(WorkOrderDTO dto) {
        if (dto.getState() == null) {
            return;
        }

        /**
         * 场景1：已完结状态，不需要展示
         * 场景2：待验证状态，仅需展示【忽略验证】+【验证问题】，也不需要展示
         * 场景3：其他状态下，仅当前处理人为登录用户时，需要展示，否则也不需要展示
         */
        if (dto.getState() == WorkOrderState.FINISHED.getCode()) {
            dto.setDisplay(false);
        } else if (dto.getState() == WorkOrderState.VERIFY.getCode()) {
            dto.setDisplay(false);
        } else {
            if (StringUtils.isEmpty(dto.getDealUser()) || StringUtils.isEmpty(ThreadContextHelper.getUserId())) {
                return;
            }
            if (dto.getDealUser().equals(ThreadContextHelper.getUserId())) {
                dto.setDisplay(true);
            } else {
                dto.setDisplay(false);
            }
        }
    }

    /**************************** 以下为测试代码，后续删除。 *****************************/
    /**
     * 模拟推送redis数据
     */
    private ConcurrentLinkedDeque<WorkOrderDTO> deque = new ConcurrentLinkedDeque<WorkOrderDTO>();
    public void mockAddRedisData(WorkOrderDTO workOrderDTO) {
        if (workOrderDTO != null) {
            this.deque.add(workOrderDTO);
        }
    }

    /**
     * 模拟从redis中拉取数据
     * @return
     */
    private WorkOrderDTO mockGetWorkOrderFromDQueue() {
        if (!this.deque.isEmpty()) {
            return this.deque.remove();
        }

        return null;
    }

    /**
     * 模拟获取质量报告
     * @return
     */
    private Map<String, Object> mockGetReport() {
        Map<String, Object> report = new HashMap<>();

        Map<String, Object> scoreInfo = new HashMap<>();
        List<Object> ruleDetailInfo = new ArrayList<>();
        Map<String, Object> basicInfo = new HashMap<>();
        report.put("scoreInfo", scoreInfo);
        report.put("ruleDetailInfo", ruleDetailInfo);
        report.put("basicInfo", basicInfo);

        basicInfo.put("jobName", "最大值检测/表行数检测");
        basicInfo.put("dbName", "wm");
        basicInfo.put("typeName", "测试节点");
        basicInfo.put("datasourceName", "试飞库");
        basicInfo.put("tableName", "student_info_tbl");
        basicInfo.put("executeTime", "2023-05-31 07:58:25");

        scoreInfo.put("result", "正常");
        scoreInfo.put("score", 0);
        scoreInfo.put("alertNum", 2);
        scoreInfo.put("ruleNum", 2);

        List<Object> rule1 = new ArrayList<>();
        ruleDetailInfo.add(rule1);
        rule1.add(1);
        rule1.add("表行数检测");
        rule1.add("表行数检测");
        rule1.add(20);
        rule1.add(4);
        rule1.add("--");
        rule1.add("--");
        rule1.add("--");
        rule1.add("--");
        rule1.add("正常");

        return report;
    }
    /********************************************************************************/
}
